package daobeauty.proxy;

import java.security.ProviderException;
import java.util.HashMap;

import daobeauty.proxy.cglib.CglibProxyProvider;
import daobeauty.proxy.javassist.JavassistProxyProvider;

/**
 * Builder class for the various implementations of {@link ProxyProvider}.
 * @see CglibProxyProvider
 * @see JavassistProxyProvider
 * @author M. Serhat Cinar
 * @since 08.09.2008
 */
public class ByteCodeProviders {
	public static final String BYTECODE_PROVIDER_CGLIB = "cglib";
	public static final String BYTECODE_PROVIDER_JAVASSIST = "javassist";
	
	private ByteCodeProviders(){}
	
	private static HashMap<String, Class<? extends ProxyProvider>> providersByName = new HashMap<String, Class<? extends ProxyProvider>>();
	static{
		register(BYTECODE_PROVIDER_CGLIB, CglibProxyProvider.class);
		register(BYTECODE_PROVIDER_JAVASSIST, JavassistProxyProvider.class);
	}
	
	public static void register(String name, Class<? extends ProxyProvider> provider){
		if (name==null || name.trim().length()<1){
			throw new IllegalArgumentException("name must not be empty");
		}
		providersByName.put(name.trim().toLowerCase(), provider);
	}
	
	public static void unregister(String name){
		if (name!=null && name.trim().length()>0){
			providersByName.remove(name.trim().toLowerCase());
		}
	}
	
	/**
	 * Create a new default {@link ProxyProvider}.
	 * 
	 * @return if cglib is available a {@link CglibProxyProvider},
	 * if no cglib is found but javassist is available returns a 
	 * {@link JavassistProxyProvider}
	 * 
	 * @throws ProviderException if neither cglib or javassist are available.
	 */
	public static ProxyProvider getInstance(){
		// check which one is available, first cglib
		try {
			Class.forName("net.sf.cglib.proxy.Enhancer");
			return getInstance(BYTECODE_PROVIDER_CGLIB);
		}
		catch (ClassNotFoundException e) {}
		
		try {
			Class.forName("javassist.util.proxy.ProxyObject");
			return getInstance(BYTECODE_PROVIDER_JAVASSIST);
		}
		catch (ClassNotFoundException e) {}
		
		throw new ProviderException("neither cglib nor javassist bytecode providers found");
	}
	
	/**
	 * Create a new {@link ProxyProvider}, defined by provider name placeholder.
	 * Legal provider name placeholders are 
	 * <ul>
	 * <li>{@link #BYTECODE_PROVIDER_CGLIB} for the cglib based 
	 *     {@link CglibProxyProvider}.</li>
	 * <li>{@link #BYTECODE_PROVIDER_JAVASSIST} for the javassist based 
	 *     {@link JavassistProxyProvider}.</li>
	 * </ul>
	 *  
	 * @param provider the placeholder value of the desired 
	 * {@link ProxyProvider} implementation.
	 * 
	 * @return a {@link ProxyProvider} implementation.
	 */
	public static ProxyProvider getInstance(String provider){
		try {
			return providersByName.get(provider.toLowerCase().trim()).newInstance();
		}
		catch (Exception e) {
			throw new IllegalArgumentException("unknown provider \""+provider+"\".", e);
		}
	}
}
